
window.print() function to open the default browser printing prompt, which provides a “print to pdf” option. It is also possible to customize the print view by adding specific CSS that applies only to printing (using the "print" media query and print-related CSS properties). This API is an excellent and simple method for printing the current page, but it doesn’t provide a clean way to export a specific UI piece. Besides, there are many cross-browser incompatibility issues with respect to printing, so we decided to try another solution.// ./ssr/src/index.js
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import MyFancyReport from './components/MyFancyReport';
export function renderStaticReport(reportProps) {
const reportMarkup = ReactDOMServer.renderToStaticMarkup(
<MyFancyReport {...reportProps} />
);
return `
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
${reportMarkup}
</body>
</html>
`;
}ReactDomServer.renderToString() function returns an HTML string for the initial state of the component. In this example, we used ReactDomServer.renderToStaticMarkup(), which also strips out all of the extra DOM attributes that are used internally by React.Document, Window, Navigator, and LocalStorage. These are not part of the Node.js runtime, and you will either have to check if they are defined and handle logic accordingly, or add a new entry point for your SSR bundle to polyfill them.ReactDomServer.renderToStaticMarkup() is a synchronous single-pass render function, which means that some hooks won’t apply, including useEffect and useState, same for lifecycle methods like componentDidMount and componentDidUpdate. It is possible, however, to use the component constructor and the componentWillMount method.// ./webpack.config.js
const path = require('path');
const webpack = require('webpack');
// existing config
const clientWebpackConfig = {
...
};
// new SSR config
const ssrWebpackConfig = {
...clientWebpackConfig,
entry: './ssr/src/index.js',
target: 'node',
output: {
path: path.resolve(__dirname, 'ssr/lib'),
filename: 'ssrService.js',
libraryTarget: 'commonjs2',
},
};
module.exports = [clientWebpackConfig, ssrWebpackConfig];npm install puppeteer// ./services/pdfService.js
const puppeteer = require('puppeteer');
const ssrService = require('../ssr/lib/ssrService.js');
const MY_PDF_PORTION = {
width: 1766,
height: 1000,
};
module.exports.generatePdfFromHtml = async (htmlStr) => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport(MY_PDF_PORTION);
await page.setContent(htmlStr, { waitUntil: 'networkidle0' });
const pdfBuffer = await page.pdf({ printBackground: true });
await browser.close();
return pdfBuffer;
};networkidle0 to make sure that dynamic resources will be available when the PDF is being generated. Also, keep in mind that there are many options for customizing the PDF.